package u1;

import gnu.trove.THashMap;
import gnu.trove.TIntHashSet;
import gnu.trove.decorator.TIntHashSetDecorator;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

/**
 * Read (uncompressed) ordinal adjacency list from stream. See AdjWriter for
 * format.
 */
public abstract class AdjReader {
  private int pageIndex;
  private int linkCount;

  public AdjReader() {
  }

  /**
   * See InputStream overload.
   * 
   * @param file
   *                not null
   * @throws IOException
   */
  public void read(File file) throws IOException {
    BufferedInputStream is = new BufferedInputStream(new FileInputStream(file));
    try {
      read(is);
    } finally {
      is.close();
    }
  }

  /**
   * Read (uncompressed) ordinal adjacency list from the given stream.
   * 
   * @param is
   *                not null; this method does not close the stream
   */
  public void read(InputStream is) {
    Scanner s = new Scanner(is, "UTF-8");
    pageIndex = 0;
    linkCount = 0;
    ArrayList<Integer> targets = new ArrayList<Integer>();
    while (s.hasNextInt()) {
      Integer source = s.nextInt();
      int numTargets = s.nextInt();
      targets.clear();
      targets.ensureCapacity(numTargets);
      for (int i = 0; i < numTargets; ++i) {
        Integer target = s.nextInt();
        targets.add(target);
      }
      readLinks(source, targets);
      ++pageIndex;
      linkCount += targets.size();
    }
  }

  /**
   * Index (starting at zero) of the page for the current call to readLinks;
   * also, the total number of pages read, after read returns.
   * 
   * @return non-negative
   */
  public int getPageIndex() {
    return pageIndex;
  }

  /**
   * Number of links read so far, not counting those in the current call to
   * readLinks.
   * 
   * @return non-negative
   */
  public int getLinkCount() {
    return linkCount;
  }

  /**
   * Subclasses override this to read in a link. Do not modify the passed
   * targets collection or store it (make a copy). The backing collection is
   * reused for efficiency reasons.
   * 
   * @param source
   *                not null, non-negative
   * @param targets
   *                not null, may be empty all entries non-negative
   */
  public abstract void readLinks(Integer source, Collection<Integer> targets);

  /**
   * Load an adjacency list into memory. Internally, Trove collections are used
   * to cut down on memory use. This can still take quite a lot of memory,
   * however. Also, you should avoid invoking entrySet for iteration on the
   * returned map (this is slow for the Trove Map).
   * 
   * @param is
   *                not null
   * @param initialHashCapacity
   *                positive; loose bound on number of pages in the adjacency
   *                list to be loaded, to avoid reallocs.
   * @return
   */
  public static Map<Integer, Set<Integer>> loadT(InputStream is,
      int initialHashCapacity) {
    final THashMap<Integer, Set<Integer>> adj = new THashMap<Integer, Set<Integer>>(
        initialHashCapacity);
    AdjReader reader = new AdjReader() {

      @Override
      public void readLinks(Integer source, Collection<Integer> targets) {
        TIntHashSet links = new TIntHashSet(targets.size());
        TIntHashSetDecorator decorator = new TIntHashSetDecorator(links);
        decorator.addAll(targets);
        adj.put(source, decorator);
      }

    };
    reader.read(is);
    return adj;
  }
}
/*
* Copyright (c) 2009 John Lees-Miller
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

